'''系统基础数据初始化脚本

功能描述：该脚本用于导入系统所需的基础数据到数据库中，包括部门、岗位、角色、菜单和用户等信息。
使用方法：直接运行 `python fixtures.py` 命令执行数据导入。
数据来源：fixtures文件夹中的JSON数据文件。

Author: 月间
Date: 2025-10-27 01:33:10
LastEditTime: 2025-11-06 21:43:10
LastEditors:  
'''
# @Version        : 1.0
# @Update Time    : 2025/10/27 2:10
# @File           : fixtures.py
# @IDE            : PyCharm
# @Desc           : 使用项目数据库与模型的初始化与数据导入脚本

import asyncio
from pathlib import Path

from advanced_alchemy.utils.fixtures import open_fixture
from sqlalchemy import text

from src.db.db_database import alchemy
from src.models import SysDept, SysMenu, SysPost, SysRole, SysUser, SysDictType, SysDictData
from src.crud.dept_repository import DeptRepo
from src.crud.menu_repository import MenuRepo
from src.crud.post_repository import PostRepo
from src.crud.role_repository import RoleRepo
from src.crud.user_repository import UserRepository
from src.crud.dict_repository import DictTypeRepo, DictDataRepo

# Fixtures 路径
fixtures_path = Path(__file__).parent / "fixtures"


async def seed_table(session, repo_cls, model_cls, fixture_name: str) -> None:
    """通用导入方法：读取指定 fixture 并批量插入对应表。

    Args:
        session: 异步数据库会话
        repo_cls: 仓库类（AdvancedAlchemy Async Repository）
        model_cls: 模型类（SQLAlchemy ORM Model）
        fixture_name: fixtures 下的 JSON 文件名（不含后缀）
    """
    try:
        print(f"Loading fixtures: {fixture_name}.json")
        data = open_fixture(fixtures_path, fixture_name)
        if not data:
            print(f"No data in {fixture_name}.json, skip.")
            return
        repo = repo_cls(session=session)
        # 将字典转换为模型实例，批量插入
        await repo.add_many([model_cls(**item) for item in data])
        await session.commit()
        print(f"Imported {len(data)} records into {model_cls.__tablename__}.")
    except FileNotFoundError:
        print(f"Fixture file not found: {fixtures_path}/{fixture_name}.json")
    except Exception as e:
        # 遇到唯一键/主键重复等错误时，打印错误并继续其他表
        print(f"Error seeding {fixture_name}: {e}")


async def seed_database() -> None:
    """按顺序导入系统所需的基础数据。
    顺序：部门 -> 岗位 -> 角色 -> 菜单 -> 用户
    """
    print("Seeding database using project async configuration...")
    async with alchemy.with_async_session() as session:
        # 先导入部门（被用户引用）
        await seed_table(session, DeptRepo, SysDept, "sys_dept")
        # 岗位
        await seed_table(session, PostRepo, SysPost, "sys_post")
        # 角色
        await seed_table(session, RoleRepo, SysRole, "sys_role")
        # 菜单
        await seed_table(session, MenuRepo, SysMenu, "sys_menu")
        # 用户（依赖部门）
        await seed_table(session, UserRepository, SysUser, "sys_user")
        # 字典类型
        await seed_table(session, DictTypeRepo, SysDictType, "sys_dict_type")
        # 字典数据
        await seed_table(session, SysDictData, SysDictData, "sys_dict_data")
        # 添加 sys_user_role 关联关系
        await session.execute(text("insert into sys_user_role (user_id, role_id) values (1, 1)"))
        # sys_user_post 关联关系
        await session.execute(text("insert into sys_user_post (user_id, post_id) values (1, 1)"))
        await session.commit()

    print("数据初始化成功.")


if __name__ == "__main__":
    asyncio.run(seed_database())